package org.flexthinker.binding.bean
{
    import mx.collections.ArrayCollection;

    import org.flexthinker.binding.form.FormModel;
    import org.flexthinker.binding.form.support.AbstractFormModel;
    import org.flexthinker.binding.form.support.DefaultFormModel;
    import org.flexthinker.binding.value.support.BufferedCollectionValueModel;
    import org.flexthinker.binding.value.support.ListValueChangeDetector;
    import org.flexthinker.binding.value.support.MockBean;
    import org.flexthinker.binding.value.support.PropertyChangeListenerCounter;
    import org.flexthinker.binding.value.support.ValueHolder;
    import org.hamcrest.assertThat;
    import org.hamcrest.core.not;
    import org.hamcrest.core.throws;
    import org.hamcrest.object.equalTo;
    import org.hamcrest.object.instanceOf;

    public class FormModelPropertyTest
    {
        private var fm:FormModel;
        private var mockBean:MockBean;
        private var fmProp:FormModelProperty;
        private var pcl:PropertyChangeListenerCounter;

        public function FormModelPropertyTest()
        {
        }

        [Before]
        public function setUp():void
        {
            mockBean = new MockBean();
            fm = new DefaultFormModel(mockBean);
            pcl = new PropertyChangeListenerCounter();
        }

        [Test]
        public function testWithString():void
        {
            fmProp = FormModelProperty.create("simpleString");
            fmProp.addValueChangeListener(pcl);
            fmProp.setSource(fm);

            mockBean.simpleString = "myNewString";
            assertThat(fmProp.getValue(), equalTo(mockBean.simpleString));
            assertThat(pcl.counter, equalTo(1));

            fmProp.setValue("Test");
            assertThat(pcl.counter, equalTo(2));

            assertThat(fmProp.getValue(), equalTo("Test"));
            assertThat("FormModel is buffered so the change shouldn't have got into the mockBean",
                    mockBean.simpleString, equalTo("myNewString"));
            assertThat(pcl.counter, equalTo(2));

            fm.commit();
            assertThat(pcl.counter, equalTo(3));
            assertThat(mockBean.simpleString, equalTo(fmProp.getValue()));
        }

        [Test]
        public function testWithNumber():void
        {
            fmProp = FormModelProperty.create("simpleNumber");
            fmProp.addValueChangeListener(pcl);
            fmProp.setSource(fm);

            mockBean.simpleNumber = 100;
            assertThat(fmProp.getValue(), equalTo(mockBean.simpleNumber));
            assertThat(pcl.counter, equalTo(1));
        }

        [Test]
        public function testWithLists():void
        {

            AbstractFormModel(fm).addValueModelFor("simpleList",
                    new BufferedCollectionValueModel(
                            new ValueHolder(mockBean, "simpleList"),
                            ArrayCollection));

            fmProp = FormModelProperty.create("simpleList");
            fmProp.addValueChangeListener(pcl);
            fmProp.setSource(fm);

            var list:ArrayCollection = new ArrayCollection(["1","2","3"]);
            mockBean.simpleList = list;
            assertThat("instances of lists should be different", fmProp.getValue(), not(equalTo(mockBean.simpleList)));
            assertThat("lists should be equal", new ListValueChangeDetector().hasValueChanged(mockBean.simpleList, fmProp.getValue()), equalTo(false));
            assertThat(pcl.counter, equalTo(1));

            fmProp.setValue( new ArrayCollection(["a","b","c"]));
            assertThat("FormModel is buffered so the change shouldn't have got into the mockBean",
                    mockBean.simpleList, equalTo(list));
            assertThat(pcl.counter, equalTo(2));

            fm.commit();
            assertThat(pcl.counter, equalTo(2));

            ArrayCollection(fmProp.getValue()).addItem("ddd");
            fm.commit();
            assertThat(pcl.counter, equalTo(3));
            assertThat("lists should be equal", new ListValueChangeDetector().hasValueChanged(mockBean.simpleList, fmProp.getValue()), equalTo(false));

        }

        //negative tests
        [Test]
        public function testWithNullSource():void
        {
            fmProp = FormModelProperty.create("simpleString");
            assertThat(function ():void
            {
                fmProp.getValue()
            },
                    throws(instanceOf(Error)));
        }

        [Test]
        public function testWithInvalidProperty():void
        {
            assertThat(function():void
            {
                FormModelProperty.create("objectHolder.simpleString");
            },
                    throws(instanceOf(ArgumentError)));
        }
    }
}
